# -*- coding: utf-8 -*-

# @File  : lark.py
# @Author: Lomo
# @Site  : lomo.space
# @Date  : 2020-02-19
# @Desc  : 通知、报警
# API Reference: https://open.feishu.cn/document/ukTMukTMukTM/uITNz4iM1MjLyUzM


import json

import requests
from functools import wraps

from config.config import LARK_CONFIG
from utils.logs import MRYT_LOG
from utils.redis_util import RedisClient


class LARK(object):
    def __init__(self):
        self.r_request = requests.session()
        self.headers = {
            'Content-Type': 'application/json'
        }

    @MRYT_LOG()
    def get_tenant_token(self):
        """
        open api token 初次申领时有效期为 7200s 即 2 小时(申领后有效期开始倒计时)
        :return: str or Boolean, token/None
        """
        r_redis = RedisClient()
        tk = r_redis.get_str('tenant_token')
        if tk:
            return tk
        else:
            req_body = {
                'app_id': LARK_CONFIG['APP_ID'],
                'app_secret': LARK_CONFIG['APP_SECRET']
            }
            res = self.r_request.post(url=LARK_CONFIG['TENANT_URL'], headers=self.headers,
                                      json=req_body)
            if res.status_code != 200:
                return None
            else:
                # 缓存 token 至 Redis
                token = res.json().get('tenant_access_token')
                exp = res.json().get('expire')
                r_redis.set_str(k='tenant_token', v=token, time=exp)
                return token

    def get_chat_list(self):
        """
        获取当前 APP 群列表
        :return: list
        """
        group_list = list()
        self.headers['Authorization'] = 'Bearer ' + self.get_tenant_token()
        response = self.r_request.get(LARK_CONFIG['GROUP_LIST_URL'], headers=self.headers)
        if response.status_code != 200:
            return None
        response_body = response.json()['data']
        if response_body.get('groups'):
            for obj in response_body.get('groups'):
                group_list.append(obj.get('chat_id'))
        return group_list

    def send_private(self, receiver, msg_card=LARK_CONFIG['MSG_CARD'], redirect_url=''):
        """
        发送通知给个人
        :param msg_card: dict, 消息卡片(https://open.feishu.cn/document/ukTMukTMukTM/ugTNwUjL4UDM14CO1ATN)
        :param receiver: str, 邮箱前缀
        :param redirect_url: str, 消息点击跳转 URL
        :return: Boolean
        """
        tenant_token = self.get_tenant_token()
        if tenant_token:
            self.headers['Authorization'] = 'Bearer ' + tenant_token
            if redirect_url:
                msg_card['card_link']['url'] = redirect_url
            body = {
                'email': receiver + LARK_CONFIG['EMAIL_SUFFIX'],
                'msg_type': 'interactive',
                'update_multi': False,
                'card': msg_card
            }

            r_msg = self.r_request.post(LARK_CONFIG['MSG_URL'], headers=self.headers,
                                        data=json.dumps(body))
            if r_msg.status_code == 200:
                return True
            else:
                return False
        else:
            return False

    def get_group_info(self, id_):
        """
        获取某个群组信息
        :param id_: str, oc_xxx(https://open.feishu.cn/document/ukTMukTMukTM/uMTO5QjLzkTO04yM5kDN)
        :return: dict
        """
        self.headers['Authorization'] = 'Bearer ' + self.get_tenant_token()
        response = self.r_request.get(LARK_CONFIG['GROUP_INFO'] + '?chat_id=' + id_, headers=self.headers)
        if response.status_code == 200:
            return response.json()['data']

    # @MRYT_LOG()
    def send_group(self, group_ids, msg=LARK_CONFIG['MSG_CARD'], redirect_url=''):
        """
        发送群消息
        :param group_ids: list, group chat_id
        :param msg: dict, 消息卡片
        :param redirect_url: str, 跳转 URL
        :return: Boolean or list
        """
        token = self.get_tenant_token()
        if token:
            self.headers['Authorization'] = 'Bearer ' + token
            if redirect_url:
                msg['card_link']['url'] = redirect_url
            fail_send = []
            for id_ in group_ids:
                body = {
                    'chat_id': id_,
                    'msg_type': 'interactive',
                    'update_multi': False,
                    'card': msg
                }
                r_msg = self.r_request.post(url=LARK_CONFIG['MSG_URL'], headers=self.headers,
                                            data=json.dumps(body))
                if r_msg.status_code != 200:
                    fail_send.append('群: {0} 发送失败, 返回错误: {1}'.format(id_, str(r_msg.json())))
                    print('发送群消息失败, 接口返回为: '.format(r_msg.json()))
            if fail_send:
                return fail_send
            else:
                return True
        else:
            return -1


class MRYTLark(object):
    def __init__(self, level='error', group=False, private=''):
        self.lark = LARK()
        self.level = level
        self.group = group
        self.private = private

    def __call__(self, func):
        @wraps(func)
        def inner_function(*args, **kwargs):
            print(func.__name__ + 'was called...')
            res = func(*args, **kwargs)
            # TODO: level 等级细化, 需要定义依赖业务 func 的返回值
            if res is None or res is '' or res != 200:
                if self.level == 'error':
                    if self.group:
                        self.lark.send_group(group_ids=self.lark.get_chat_list())
                    if self.private:
                        self.lark.send_private(receiver=self.private)

            return res
        return inner_function
